package com.seari.ats.handler;

import java.util.ArrayList;
import java.util.List;

import com.seari.ats.AtsHelper;
import com.seari.bean.ats.AtsFrameInstruct;
import com.seari.utils.DataUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AtsDecoder extends ByteToMessageDecoder {

	protected static Logger logger = LoggerFactory.getLogger(AtsDecoder.class);

	@Override
	public void decode(ChannelHandlerContext ctx, ByteBuf in,List<Object> out) throws Exception {
		List<AtsFrameInstruct> allFrame = new ArrayList<AtsFrameInstruct>();
		// 标记一下当前的readIndex的位置
		in.markReaderIndex();
		//只寻找 0xff
		int firstByte = in.readByte();
		if(firstByte != (byte)0xff){
			return;
		}
		//小于最小帧长直接返回
		if (in.readableBytes() < AtsHelper.FRAME_LENGTH_WITHOUT_PACKAHE_DATA-1) {
			logger.warn("小于最小帧长直接返回  单个帧最小长度小于8");
			return;
		}
		byte[] frameHeadInfo = new byte[3];
		in.readBytes(frameHeadInfo);
		//Package-Data 长度
		int packageDataTotalLength = DataUtil.getHighLowByteValue(frameHeadInfo[0], frameHeadInfo[1])-1;
		if (in.readableBytes() < packageDataTotalLength) {
			logger.debug("包长不够时重置读指针等待下次包数据");
			in.resetReaderIndex();
			return;
		}
		//有无后续帧  0   1
		int multiFlag = frameHeadInfo[2]& 0xFF;
		logger.debug("可读长度="+in.readableBytes()+" 有无后续帧="+multiFlag+" Package-Data长度="+packageDataTotalLength);
		//没有后续帧
		if(multiFlag==0) {
			if(packageDataTotalLength>1024){
				logger.warn("单个帧中 Package-Data部分最大长度是 1024  大于直接返回");
				return;
			}
			AtsFrameInstruct atsFrameInstructFirst = new AtsFrameInstruct();
			//帧头部信息
			atsFrameInstructFirst.setSystem_id(firstByte & 0xFF);
			//这边指定的是Package-Data 长度
			atsFrameInstructFirst.setTotal_length(packageDataTotalLength);
			atsFrameInstructFirst.setMulti_flag(multiFlag);
			//取出package中的字节数据放到数组里面后续再处理-------取出固定长度的数据   防止粘帧！！！------------------------------------
			byte[] package_data = new byte[packageDataTotalLength];
			in.readBytes(package_data);
			atsFrameInstructFirst.setPackage_data(package_data);
			//帧package信息
			allFrame.add(atsFrameInstructFirst);
		}
		//有后续帧处理   轮询取数据帧依次放到集合中
		if(multiFlag==1) {
			//第一帧处理  帧头部信息
			AtsFrameInstruct atsFrameInstructFirst = new AtsFrameInstruct();
			atsFrameInstructFirst.setSystem_id(firstByte & 0xFF);
			//这边指定的是Package-Data 长度
			atsFrameInstructFirst.setTotal_length(packageDataTotalLength);
			atsFrameInstructFirst.setMulti_flag(multiFlag);
			//取出package中的字节数据放到数组里面后续再处理-------取出固定长度的数据   防止粘帧！！！------------------------------------
			byte[] package_data = new byte[packageDataTotalLength];
			in.readBytes(package_data);
			atsFrameInstructFirst.setPackage_data(package_data);
			allFrame.add(atsFrameInstructFirst);

			//在取后续帧的信息
			List<AtsFrameInstruct> atsFrameInstructList = new ArrayList<AtsFrameInstruct>();
			atsFrameInstructList = getFollowFrameListInfo(in);
			//包长不够时重置读指针等待下次包数据
			if(null==atsFrameInstructList){
				logger.debug("后续帧包长不够时重置读指针等待下次包数据");
				in.resetReaderIndex();
				return;
			}
			allFrame.addAll(atsFrameInstructList);
		}
		logger.debug("===该批次下帧所有信息==="+allFrame);
		out.add(allFrame);
	}

	/**
	 * 后续帧读取
	 * @param in
	 * @return
	 */
	public List<AtsFrameInstruct> getFollowFrameListInfo(ByteBuf in){
		List<AtsFrameInstruct> atsFrameInstructList = new ArrayList<AtsFrameInstruct>();
		boolean notHaveFullBoo = false;
		while(true){
			//只寻找 0xff
			int firstByte = in.readByte();
			if(firstByte == (byte)0xff){
				byte[] frameHeadInfo = new byte[3];
				in.readBytes(frameHeadInfo);
				int packageDataTotalLength = DataUtil.getHighLowByteValue(frameHeadInfo[0], frameHeadInfo[1])-1;
				if (in.readableBytes() < packageDataTotalLength) {
					//包长不够
					notHaveFullBoo = true;
					break;
				}
				int multiFlag = frameHeadInfo[2]& 0xFF;
				byte[] package_data = new byte[packageDataTotalLength];
				in.readBytes(package_data);
				//后续帧处理
				AtsFrameInstruct atsFrameInstruct = new AtsFrameInstruct();
				atsFrameInstruct.setSystem_id(firstByte & 0xFF);
				atsFrameInstruct.setTotal_length(packageDataTotalLength);
				atsFrameInstruct.setMulti_flag(multiFlag);
				atsFrameInstruct.setPackage_data(package_data);
				atsFrameInstructList.add(atsFrameInstruct);
				//最后一次处理帧，没有后续帧标识结束循环
				if(0==multiFlag){
					logger.debug("后续帧读取完毕结束循环！！！");
					//logger.debug("===AtsDecoder.getFollowFrameListInfo.readableBytes==="+in.readableBytes());
					break;
				}
			}
		}
		if(notHaveFullBoo){//true 包长不够
			return null;
		}else{//包长够了
			return atsFrameInstructList;
		}
	}
}